package com.study.netty.server.handle;

import cn.hutool.core.util.StrUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName ServerInboundHandler
 * @Description 该类的主要作用是用来接收客户端推送过来的消息
 * @Author csc
 * @Date 2023/5/16 10:47
 * @Version 1.0
 */

@Slf4j
@Component
@ChannelHandler.Sharable
public class ServerInboundHandler  extends ChannelInboundHandlerAdapter {



    public static Map<String, ChannelHandlerContext> CHANNEL_MAP = new ConcurrentHashMap<>();

    public ServerInboundHandler() {
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端初始化 name:{},ip:{}", ctx.name(), ctx.channel().remoteAddress().toString());
        String channelId = ctx.channel().id().asShortText();

        if (CHANNEL_MAP.containsKey(channelId)) {
            log.info("客户端【{}】是连接状态，连接通道数量:{}", channelId, CHANNEL_MAP.size());
        }else{
            InetSocketAddress inetSocketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
            String clientIp = inetSocketAddress.getAddress().getHostAddress();
            int clientPort = inetSocketAddress.getPort();
            // 保存连接
            CHANNEL_MAP.put(channelId, ctx);
            log.info("客户端【{}】连接Netty服务端!![clientIp:{} clientPort:{}]", channelId, clientIp, clientPort);
            log.info("连接通道数量:{}", CHANNEL_MAP.size());
        }
        super.channelActive(ctx);
    }

    /**
     * 当客户端主动断开连接，通道不活跃触发
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端断开连接 name:{},ip:{}", ctx.name(), ctx.channel().remoteAddress().toString());
        String channelId = ctx.channel().id().asShortText();
        CHANNEL_MAP.remove(channelId);
        super.channelInactive(ctx);
    }

    /**
     *  有消息写入通道
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        log.info("收到消息 data:{}", ((ByteBuf) msg).toString(StandardCharsets.UTF_8));
// 【0】创建新的buf进行恢复
        ByteBuf respBuf = ctx.alloc().buffer();

// 【2】可以交给其他服务处理消息，再写入回复【针对需要消息应答的机制，如果不需要应答可忽略】
        respBuf.writeBytes("回复".getBytes(StandardCharsets.UTF_8));
// 注意：不要使用ctx的writeAndFlush，他不是从尾开始扫描，无法写入
        ctx.channel().writeAndFlush(respBuf);
        channelWrite(null, "回12312312复");
        super.channelRead(ctx, msg);
    }

    /**
     * 当连接发生异常时触发
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("netty 服务器出现异常");
        super.exceptionCaught(ctx, cause);
    }

    /**
     * <p>用于 通知所有的客户端、根据业务需求用，配合 ctx上下文map配套使用</p>
     * @param channelId 通道id
     * @param msg 消息
     */
    public void channelWrite(String channelId, String msg) {
        log.info("发送消息 channelId:{} msg:{}", channelId, msg);
        if(StrUtil.isNotBlank(channelId)){
            ChannelHandlerContext ctx = CHANNEL_MAP.get(channelId);
            if (msg != null) {
                ctx.channel().writeAndFlush(msg.getBytes(StandardCharsets.UTF_8));
            }
        }else{
            for (Map.Entry<String, ChannelHandlerContext> entry : CHANNEL_MAP.entrySet()) {
                entry.getValue().channel().writeAndFlush(msg);
            }

        }
    }//end



}
